package com.diorsunion.hedge.io.netty;

import com.google.common.collect.Maps;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import javax.annotation.Resource;
import java.util.Map;


/**
 * Netty服务端配置
 * @author wangnima
 *
 */
@Configuration
@PropertySource("classpath:config/netty-server.properties")
public class NettyServerConfig {
	@Value("${netty.boss.thread.count}")
	int bossCount;
	@Value("${netty.worker.thread.count}")
	int workerCount;
	@Value("${netty.so.keepalive}")
	boolean keepAlive;
	@Value("${netty.so.backlog}")
	int backlog;
	@Value("${netty.idle.reader}")
	int readerIdleTimeSeconds;
	@Value("${netty.idle.writer}")
	int writerIdleTimeSeconds;
	@Value("${netty.idle.all}")
	int allIdleTimeSeconds;

	@Value("${kryo.pool.maxTotal}")
	int maxTotal;
	@Value("${kryo.pool.minIdle}")
	int minIdle;
	@Value("${kryo.pool.maxWaitMillis}")
	long maxWaitMillis;
	@Value("${kryo.pool.minEvictableIdleTimeMillis}")
	long minEvictableIdleTimeMillis;

	@Resource
	NettyServerHandler nettyServerHandler;
	@Resource @Qualifier("BossGroup")
	NioEventLoopGroup  bossGroup;
	@Resource @Qualifier("WorkerGroup")
	NioEventLoopGroup workerGroup;

	@Resource
	ApplicationContext context;

	@Bean(name = "ServerBootstrap")
	public ServerBootstrap bootstrap() {
		ServerBootstrap b = new ServerBootstrap();
		b.group(bossGroup, workerGroup)
				.channel(NioServerSocketChannel.class)
				.childHandler(getProtocolInitalizer());
		Map<ChannelOption, Object> tcpChannelOptions = tcpChannelOptions();
		tcpChannelOptions.forEach((k, v) -> b.option(k, v));
		return b;
	}

	public NettyChannelInitializer getProtocolInitalizer(){
		KryoPool kryoPool = new KryoPool(maxTotal,minIdle,maxWaitMillis,minEvictableIdleTimeMillis);
		NettyChannelInitializer protocolInitalizer =
				new NettyChannelInitializer(
						kryoPool,
						nettyServerHandler,
						readerIdleTimeSeconds, writerIdleTimeSeconds, allIdleTimeSeconds);
		return protocolInitalizer;
	}

	@Bean(name = "TcpChannelOptions")
	public Map<ChannelOption,Object> tcpChannelOptions() {
		Map<ChannelOption, Object> options = Maps.newHashMap();
		options.put(ChannelOption.SO_KEEPALIVE, keepAlive);//长连接
		options.put(ChannelOption.SO_BACKLOG, backlog);
		options.put(ChannelOption.TCP_NODELAY, true);//立即发送,不延迟
		return options;
	}

	@Bean(name = "BossGroup")
	public NioEventLoopGroup getBossGroup(){
		NioEventLoopGroup bossGroup  = new NioEventLoopGroup(bossCount);
		return bossGroup;
	}

	@Bean(name = "WorkerGroup")
	public NioEventLoopGroup getWorkerGroup(){
		NioEventLoopGroup workerGroup = new NioEventLoopGroup(workerCount);
		return workerGroup;
	}
}

